/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       creature_count.h

	$Header: /game/creature_count.h $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#include "creature_array.h"

#include <algorithm>

#include "adventure_frame.h"
#include "adventure_map.h"
#include "ai_army_data_cache.h"
#include "ai_importance.h"
#include "ai_value.h"
#include "alignment_relationship.h"
#include "army.h"
#include "basic_dialog.h"
#include "building_traits.h"
#include "creature_traits.h"
#include "creature_type.h"
#include "creature.h"
#include "direction.h"
#include "elements_of.h"
#include "enum_operations.h"
#include "external_string.h"
#include "formation_type.h"
#include "game_replace_keywords.h"
#include "get_artifact_damage_modifier.h"
#include "hero.h"
#include "null_grail_data_source.h"
#include "player.h"
#include "streambuf_operators.h"
#include "town_type.h"

static int const k_current_save_version = 3;

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
t_creature_array::t_creature_array() : m_patrol_type(k_patrol_none), m_patrol_radius(-1), m_ai_importance( k_ai_importance_normal )

{
	int i;

	for (i = 0; i < k_size; i++)
		m_data[i] = new t_creature_stack;

	m_initial_location.row		 = -1;
	m_initial_location.column	 = -1;
	m_initial_location.level	 = -1;
	m_initial_location.on_bridge = false;
	m_formation = k_formation_loose;

	m_ai_data_cache = new t_ai_army_data_cache;
}

// ------------------------------------------------------
// move contents of one creature array to another
// ------------------------------------------------------
t_creature_array::t_creature_array( t_creature_array* source ) : 
	m_initial_location( source->m_initial_location ),
	m_patrol_type( source->m_patrol_type ), m_patrol_radius( source->m_patrol_radius )
{
	for (int i = 0; i < k_size; ++i)
		m_data[i] = source->m_data[i];
	source->clear();

	m_ai_importance = source->m_ai_importance;
	m_formation = source->m_formation;
	m_ai_data_cache = source->m_ai_data_cache;
	source->m_ai_data_cache = new t_ai_army_data_cache;
}

void t_creature_array::move_creatures_from( t_creature_array& source )
{
	int i;

	for (i = 0; i < k_size; ++i)
	{
		if (m_data[i]->get_number() == 0)
		{
			m_data[i] = source.m_data[i];
			source.clear( i );
		}
	}
}

// ------------------------------------------------------
// array of creatures and/or heroes
// destroy array
// ------------------------------------------------------
t_creature_array::~t_creature_array()
{
}


// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
void t_creature_array::clear()
{
	int i; 

	for (i = 0; i < k_size; i++)
		if (m_data[i]->get_number() != 0)
			m_data[i] = new t_creature_stack;
	
	post_change();
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
void t_creature_array::clear( int slot )
{
	if (m_data[slot]->get_number() != 0)
		m_data[slot] = new t_creature_stack;

	post_change();
}


// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
int t_creature_array::find( t_hero const* hero ) const
{
	int i;

	for (i = 0; i < k_size; i++)
		if (m_data[i] == hero)
			return i;
	return -1;
}

int t_creature_array::find( t_creature_type creature_type ) const
{
	int i;

	for (i = 0; i < k_size; i++)
		if (m_data[i]->get_creature() != 0
			&& m_data[i]->get_creature()->get_creature_type() == creature_type)
			return i;
	return -1;
}


// ------------------------------------------------------
// array of creatures and/or heroes
// Get the grail data we should use for any creature in
// this army
// ------------------------------------------------------
t_abstract_grail_data_source const & t_creature_array::get_grail_data() const
{
	t_player * owner = get_owner();

	if ( owner )
		return *owner;
	else
		return t_null_grail_data_source::get();
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
int t_creature_array::get_hero_count() const
{
	int result = 0;
	int i;

	for (i = 0; i < k_size; i++)
		if (m_data[i]->get_hero() != 0)
			result++;
	return result;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
int t_creature_array::get_living_hero_count() const
{
	int result = 0;
	int i;

	for (i = 0; i < k_size; i++)
		if (m_data[i]->get_hero() != 0 && !m_data[i]->is_dead())
			result++;
	return result;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
bool t_creature_array::add( t_creature_stack_ptr arg, int index )
{
	if (index < 0)
	{
		for (index = 0; index < k_size; index++)
			if (m_data[index]->get_number() > 0 && m_data[index]->can_add( *arg ))
				break;
		if (index == k_size)
		{
			for (index = 0; index < k_size; index++)
				if (m_data[index]->can_add( *arg ))
					break;
			if (index == k_size)
				return false;
		}
	}

	if (!m_data[index]->can_add( *arg ))
		return false;
	if (m_data[index]->get_number() == 0)
		m_data[index] = arg;
	else
		m_data[index]->get_creature()->add( *arg->get_creature() );

	post_change();

	return true;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
void t_creature_array::remove( int amount, int slot )
{
	if (m_data[slot]->get_number() == amount)
		clear( slot );
	else
		m_data[slot]->remove( amount );

	post_change();
}


// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
bool t_creature_array::can_add( t_creature_type creature ) const
{
	int index;

	for (index = 0; index < k_size; index++)
		if (m_data[index]->can_add( creature ))
			return true;
	return false;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
bool t_creature_array::can_add_hero() const
{
	int index;

	for (index = 0; index < k_size; index++)
		if (m_data[index]->get_number() == 0)
			return true;
	return false;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
bool t_creature_array::empty() const
{
	int index;

	for (index = 0; index < k_size; index++)
		if (m_data[index]->get_number() > 0)
			return false;
	return true;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
int t_creature_array::get_empty_slot_count() const
{
	int result = 0;
	int index;
	for ( index = 0; index < k_size; ++index )
	{
		if ( m_data[ index ]->get_number() == 0 )
			++result;
	}
	return result;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
int t_creature_array::get_fastest_raw_move() const
{
	int i;
	int speed;
	int fastest = 0;
	t_creature_stack const*	stack;

	// check if we have creatures.  If so, find the best movement cost in Action Points.
	for (i = 0; i < k_size; i++)
	{
		stack = m_data[i];
		if (stack->get_creature() == 0)
			continue;

		speed = stack->get_raw_adventure_movement();
		if (speed > fastest)
			fastest = speed;
	}
	return fastest;
}


// ------------------------------------------------------
// array of creatures and/or heroes
// set all movement to zero
// ------------------------------------------------------
void t_creature_array::expend_all_movement()
{
	int  i;

	for (i = 0; i < k_size; i++)
	{
		if (m_data[i]->get_number() == 0)
			continue;

		m_data[i]->set_raw_adventure_movement( 0 );
	}
}

// ------------------------------------------------------
// array of creatures and/or heroes
// set all movement to no more than max_remaining_movement
// ------------------------------------------------------
void t_creature_array::expend_most_movement( int max_remaining_movement )
{
	bool				in_boat = is_boat();
	float				move_bonus = get_move_bonus( in_boat );
	float				multiplier = get_move_multiplier( in_boat );
	float				fastest_raw_move = get_fastest_raw_move();
	float				modifier;
	int					movement;
	t_creature_stack *  stack;

	int  i;

	for (i = 0; i < k_size; i++)
	{
		stack = m_data[i];
		if (stack->get_number() == 0)
			continue;

		modifier = stack->get_adventure_movement_modifier( move_bonus, multiplier,
														   fastest_raw_move );

		movement = stack->get_raw_adventure_movement_left() * modifier;

		if ( movement > max_remaining_movement && modifier > 0.0 )
			stack->set_raw_adventure_movement( max_remaining_movement / modifier);
	}
}


// ---------------------------------------------------------------
// army which appears on the adventure map
// determine cost of moving
// ---------------------------------------------------------------
int t_creature_array::get_move_cost( t_terrain_type terrain ) const
{
	int						result = 0;
	int						cost;
	int						i;
	t_creature_stack const* stack;

	// determine cost due to native terrain
	// use highest cost
	for (i = 0; i < t_creature_array::k_size; ++i)
	{
		stack = m_data[i];
		if (stack->get_number() == 0 || stack->is_dead())
			continue;
		// don't count heroes.
		if (stack->get_hero() != 0)
			continue;
		cost = stack->get_move_cost( terrain );
		if (result < cost)
			result = cost;
	}
	if (result == 0)
		result = get_terrain_cost( terrain );

	// determine modifiers due to hero skill or artifacts
	// use smallest cost
	for (i = 0; i < k_size; ++i)
	{
		stack = m_data[i];
		if (stack->get_number() == 0 || stack->is_dead())
			continue;
		cost = stack->get_army_move_cost( terrain );
		if (result > cost)
			result = cost;
	}
	return result;
}


// ------------------------------------------------------
// array of creatures and/or heroes
// find the "leader" index - highest-level hero, or toughest creature.
// ------------------------------------------------------
int t_creature_array::get_leader_index() const
{
	int i;
	int result = 0;
	t_hero const*           hero;
	t_hero const*           leader_hero;
	t_creature_stack const* leader = m_data[0];

	leader_hero = leader->get_hero();
	for (i = 0; i < k_size; i++)
	{
		if (m_data[i]->get_number() == 0)
			continue;

		hero = m_data[i]->get_hero();
		if (leader->get_number() > 0)
		{
			// if leader is dead, any non-dead leader is better
			if (!leader->is_dead() && m_data[i]->is_dead())
				continue;
			if (leader->is_dead() == m_data[i]->is_dead())
			{
				// if leader is a hero, new leader must be a higher-ranking hero
				if (leader_hero != 0)
				{
					if (hero == 0)
						continue;

					if (leader_hero->get_level() >= hero->get_level())
						continue;
				}
				else if (hero == 0) // if leader is not a hero, any hero will do
				{
					// if neither is a hero, take the tougher one.
					if (get_traits( leader->get_creature()->get_creature_type() ).experience >=
						get_traits( m_data[i]->get_creature()->get_creature_type() ).experience )
						continue;
				}
			}
		}

		result = i;
		leader = m_data[i];
		leader_hero = hero;
	}

	return result;
}

// ------------------------------------------------------
// ------------------------------------------------------
t_hero* t_creature_array::get_strongest_hero()
{
	t_hero*	hero;
	t_hero* strongest_hero = NULL;
	int		strongest_value = -1;
	
	for (int loop = 0; loop < k_size; loop++) 
	{
		hero = m_data[loop]->get_hero();

		if (hero && (hero->is_dead() == false)) {
			int skill_total = 0;
			std::vector<t_skill>& skills = hero->get_skills();
			int skill_count = skills.size();
			for (int i = 0; i < skill_count; i++) 
			{
				skill_total += (skills[i].level + 1);
			}

			if (skill_total > strongest_value) {
				strongest_hero = hero;
				strongest_value = skill_total;
			}
		}
	}

	return strongest_hero;
}

// ------------------------------------------------------
// ------------------------------------------------------
t_hero const* t_creature_array::get_strongest_hero() const
{
	return const_cast<t_creature_array*>(this)->get_strongest_hero();
}

// ------------------------------------------------------
// ------------------------------------------------------
t_hero* t_creature_array::get_weakest_hero() 
{
	t_hero*	hero;
	t_hero* weakest_hero = NULL;
	int		weakest_value = -1;
	
	for (int loop = 0; loop < k_size; loop++) 
	{
		hero = m_data[loop]->get_hero();

		if (hero && (hero->is_dead() == false)) {
			int skill_total = 0;
			std::vector<t_skill>& skills = hero->get_skills();
			int skill_count = skills.size();
			for (int i = 0; i < skill_count; i++) 
			{
				skill_total += (skills[i].level + 1);
			}

			if ((skill_total < weakest_value) || (weakest_value == -1)) {
				weakest_hero = hero;
				weakest_value = skill_total;
			}
		}
	}

	return weakest_hero;
}

// ------------------------------------------------------
// ------------------------------------------------------
t_hero const* t_creature_array::get_weakest_hero() const
{
	return const_cast<t_creature_array*>(this)->get_weakest_hero();
}

// ------------------------------------------------------
// ------------------------------------------------------
t_hero* t_creature_array::get_any_hero() 
{
	t_hero* hero;

	for (int loop = 0; loop < k_size; loop++) 
	{
		hero = m_data[loop]->get_hero();
		if (hero && (hero->is_dead() == false)) 
			return hero;
	}
	return NULL;
}

// ------------------------------------------------------
// ------------------------------------------------------
t_hero const* t_creature_array::get_any_hero() const
{
	return const_cast<t_creature_array*>(this)->get_any_hero();
}

// ------------------------------------------------------
// array of creatures and/or heroes
// Is this creature stack a graveyard army?
// ------------------------------------------------------
bool t_creature_array::is_graveyard() const
{
	return false;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// get remaining action points
// ------------------------------------------------------
void t_creature_array::process_new_day( bool grow )
{
	int				 i;
	t_adventure_map* map = get_map();
	t_player*		 owner = get_owner();
	int				 day = 0;
	bool			 boat = is_boat();

	if (map != 0)
		day = map->get_day();
	for (i = 0; i < k_size; i++)
	{
		if (m_data[i]->get_number() == 0)
			continue;
		m_data[i]->process_new_day( owner, grow, this, day );
	}
}

// ------------------------------------------------------
// array of creatures and/or heroes
// add an artifact to the army
// ------------------------------------------------------
bool t_creature_array::add( t_artifact const& artifact )
{
	if (empty())
		return false;

	t_creature_stack& leader = const_cast<t_creature_stack&>(get_leader());

	return leader.add( artifact );
}

// ------------------------------------------------------
// array of creatures and/or heroes
// all creatures learn spells from town
// ------------------------------------------------------
void t_creature_array::learn_spells( t_town const* town )
{
	int i;

	for (i = 0; i < k_size; i++)
		m_data[i]->learn_spells( town );
}

// ------------------------------------------------------
// array of creatures and/or heroes
// all creatures learn spells from town
// ------------------------------------------------------
int t_creature_array::get_morale( t_town_type arg ) const
{
	static int  modifiers[] = { 0, -1, -2, -5 };

	bool        has_alignment[k_town_type_count];
	bool        has_undead = false;
	int         i;
	t_town_type alignment;
	int         result = 1;

	memset( has_alignment, 0, sizeof( has_alignment ));
	for (i =0 ; i < k_size; i++)
	{
		if (m_data[i]->get_number() == 0)
			continue;
		has_alignment[m_data[i]->get_alignment()] = true;
		if (m_data[i]->is_undead())
			has_undead = true;
	}
	for (alignment = t_town_type(0); alignment < k_town_type_count; enum_incr( alignment ))
	{
		if (has_alignment[alignment])
			result += modifiers[get_alignment_relationship( arg, alignment )];
	}
	if (has_undead && arg != k_town_death)
		result -= 2;
	return result;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// write to save game
// ------------------------------------------------------
namespace
{
	enum
	{
		k_stack_none,
		k_stack_creature,
		k_stack_hero
	};
};


bool t_creature_array::write( std::streambuf& stream ) const
{
	int               i;
	t_creature const* creature;
	t_hero const*     hero;

	put<t_uint16>( stream, k_current_save_version );
	for (i = 0; i < k_size; i++)
	{
		creature = m_data[i]->get_creature();
		if (creature != 0)
		{
			put<t_uint8>(stream, k_stack_creature );
			creature->write( stream );
			continue;
		}
		hero = m_data[i]->get_hero();
		if (hero != 0)
		{
			put<t_uint8>( stream, k_stack_hero );
			hero->write( stream );
			continue;
		}
		put<t_uint8>( stream, k_stack_none );
	}

	put< t_int32 >( stream, m_initial_location.row );
	put< t_int32 >( stream, m_initial_location.column );
	put< t_int8 >( stream, 	m_initial_location.level );
	put< t_uint8 >( stream, m_initial_location.on_bridge );
	put< t_uint8 >( stream, m_patrol_type );
	put< t_uint8 >( stream, m_patrol_radius );
	put< t_int8 >( stream, m_formation );
	put< t_ai_importance >( stream, m_ai_importance );
	
	return true;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// read from save game
// ------------------------------------------------------
bool t_creature_array::read_version( std::streambuf& stream, int version )
{
	if ( version < 0 || version > k_current_save_version )
		return false;

	int i;

	for (i = 0; i < k_size; i++)
	{
		switch (get<t_uint8>( stream ))
		{
			case k_stack_none:
				m_data[i] = new t_creature_stack;
				break;

			case k_stack_creature:
				m_data[i] = new t_creature;
				break;

			case k_stack_hero:
				m_data[i] = new t_hero;
				break;

			default:
				return false;
		}
		if (!m_data[i]->read( stream ))
			return false;
	}

	if ( version >= 1 )
	{
		m_initial_location.row		 = get< t_int32 >( stream );
		m_initial_location.column	 = get< t_int32 >( stream );
		m_initial_location.level	 = get< t_int8 >( stream );
		m_initial_location.on_bridge = ( get< t_uint8 >( stream ) != 0 );
		m_patrol_type = t_patrol_type( get< t_uint8 >( stream ) );
		m_patrol_radius = get< t_uint8 >( stream );
	}
	else
	{
		m_initial_location.row		 = -1;
		m_initial_location.column	 = -1;
		m_initial_location.level	 = -1;
		m_initial_location.on_bridge = false;
	}
	if (version < 2)
		m_formation = k_formation_loose;
	else
		m_formation = t_formation_type( get<t_int8>( stream ));

	if (version < 3)
		m_ai_importance = k_ai_importance_normal;
	else
		m_ai_importance = get< t_ai_importance >( stream );

	post_change();

	return true;
}

bool t_creature_array::read( std::streambuf& stream )
{
	int version = get<t_uint16>( stream );
	
	return read_version( stream, version );
}
// ------------------------------------------------------
// array of creatures and/or heroes
// Call after read to finish initialization
// ------------------------------------------------------
void t_creature_array::read_postplacement( t_adventure_map & map )
{
	if ( m_initial_location.level == -1 )
	{
		m_initial_location = get_position();
	}

	for ( int i = 0; i < k_size; i++ )
	{
		m_data[i]->read_postplacement( map );
	}
}


// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
namespace
{
	// Of course, the map files use different values for the stack types
	enum t_map_file_stack_type
	{
		k_map_stack_none = -1,
		k_map_stack_creature,
		k_map_stack_hero,
	};

	t_creature_stack_ptr reconstruct_stack_from_map( std::streambuf& stream )
	{
		t_creature_stack_ptr result;

		t_map_file_stack_type stack_type = t_map_file_stack_type( get< t_int8 >( stream ) );
		switch ( stack_type )
		{
		case k_map_stack_none:
			result = new t_creature_stack;
			break;

		case k_map_stack_creature:
			result = new t_creature;
			break;

		case k_map_stack_hero:
			result = new t_hero;
			break;

		default:
			return t_creature_stack_ptr();
		}

		if ( !result->read_from_map( stream ) )
			return t_creature_stack_ptr();

		return result;
	}
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
bool t_creature_array::read_from_map( std::streambuf& stream )
{
	int const k_current_format_version = 0;

	int format_version = get< t_uint16 >( stream );
	if ( format_version < 0 || format_version > k_current_format_version )
		return false;

	t_creature_stack_ptr new_data[ k_size ];
	int slot_num;
	for ( slot_num = 0; slot_num < k_size; ++slot_num )
	{
		t_creature_stack_ptr & stack_ptr = new_data[ slot_num ];
		stack_ptr = reconstruct_stack_from_map( stream );
		if ( stack_ptr.get() == 0 )
			return false;
	}

	std::copy( &new_data[ 0 ], &new_data[ k_size ], &m_data[ 0 ] );

	post_change();

	return true;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
bool t_creature_array::read_summary_from_map( std::streambuf& stream )
{
	int const k_current_format_version = 0;

	int format_version = get< t_uint16 >( stream );
	if ( format_version < 0 || format_version > k_current_format_version )
		return false;

	t_creature_stack_ptr new_data[ k_size ];
	new_data[ 0 ] = reconstruct_stack_from_map( stream );
	if ( new_data[ 0 ].get() == 0 )
		return false;

	int slot_num;
	for ( slot_num = 1; slot_num < k_size; ++slot_num )
		new_data[ slot_num ] = new t_creature_stack;

	std::copy( &new_data[ 0 ], &new_data[ k_size ], &m_data[ 0 ] );
	
	post_change();

	return true;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// Call after read_from_map to finish initialization
// ------------------------------------------------------
void t_creature_array::initialize()
{
	m_initial_location = get_position();
}

// ------------------------------------------------------
// array of creatures and/or heroes
// add new creatures to an army
// ------------------------------------------------------
bool t_creature_array::add( t_creature_type creature, int amount, int index )
 // newly-created creatures
{
	t_creature_stack_ptr creatures;

	creatures = new t_creature( creature, amount );
	creatures->process_new_day( 0, false, NULL, 0 );
	return add( creatures, index );
}

// ------------------------------------------------------
// array of creatures and/or heroes
// get total experience value of army
// ------------------------------------------------------
int t_creature_array::get_experience_value() const
{
	int i;
	int result = 0;

	for (i = 0; i < k_size; i++)
		result += m_data[i]->get_experience_value();
	return result;
}

extern t_external_string const k_max_level_reached;
extern t_external_string const k_max_level_reached_title;
static t_external_string const k_max_level_reached_multiple( "max_level_reached_multiple.misc" );

// ------------------------------------------------------
// array of creatures and/or heroes
// add experience to an army
// ------------------------------------------------------
void t_creature_array::add_experience( int amount, t_window* parent, bool evenly )
{
	int     total_weight = 0;
	int		hero_weight[k_size];
	int     i;

	for (i = 0; i < k_size; i++)
	{
		t_hero* hero = m_data[i]->get_hero();
		if (hero != 0 && !hero->is_dead())
		{
			if (evenly)
				hero_weight[i] = 1;
			else
				hero_weight[i] = hero->get_level() + 2;
			total_weight += hero_weight[i];
		}
		else
			hero_weight[i] = 0;
	}
	if (total_weight == 0)
		return;

	int			awards[ k_size ];
	bool		need_max_experience_dialog = false;
	bool		hero_maxed_out_flags[ k_size ];
	t_hero *	heroes[ k_size ];
	t_player *	owner = get_owner();

	for ( i = 0; i < k_size; i++ )
	{
		awards[i] = 0;
		hero_maxed_out_flags[i] = false;
		heroes[i] = m_data[i]->get_hero();
	}

	// Split the reward between the heroes; don't "waste" experience unless
	// we have no choice
	bool still_working = true;

	while ( amount > 0 && still_working)
	{
		int current_total_weight = total_weight;

		// Split experience amoung heroes
		for (i = 0; i < k_size; i++)
		{
			if (heroes[i] == 0)
				continue;

			if (heroes[i]->is_dead())
				continue;

			if ( hero_maxed_out_flags[i] )
				continue; // Already maxed out

			int weight		= hero_weight[i];
			int new_award	= double(weight) * amount / current_total_weight + 0.5;

			awards[i] += new_award;
			amount -= new_award;
			current_total_weight -= weight;
		}

		if ( owner && owner->has_max_level() )
		{
			still_working = false;

			// Check for over-awarding 
			for (i = 0; i < k_size; i++)
			{
				if (heroes[i] == 0)
					continue;

				if (heroes[i]->is_dead())
					continue;

				if ( hero_maxed_out_flags[i] )
					continue; // Already maxed out

				int experience_limit = heroes[i]->get_experience( owner->get_max_level() );
				int current_experience = awards[i] + heroes[i]->get_experience();

				if ( current_experience >  experience_limit )
				{
					hero_maxed_out_flags[i] = true;
					need_max_experience_dialog = true;
					amount += current_experience - experience_limit;
					awards[i] = experience_limit - heroes[i]->get_experience();
					total_weight -= hero_weight[i];
					still_working = true;
				}
			}
		}
	}

	for ( i = 0; i < k_size; i++ )
	{
		if ( heroes[i] )
			heroes[i]->add_experience( awards[i], get_map(), owner, parent );
	}

	if ( need_max_experience_dialog && (!get_owner()->is_computer()) )
	{
		std::vector<t_hero*> maxed_out_heroes;

		for ( i = 0; i < k_size; i++ )
		{
			// Check the hero's max experience flag to ensure we only display the
			// maxed out experience dialog once per hero
			if ( hero_maxed_out_flags[i] && !heroes[i]->get_max_experience_flag() )
			{
				maxed_out_heroes.push_back( heroes[i] );
				heroes[i]->set_max_experience_flag();
			}
		}

		if ( !maxed_out_heroes.empty() )
		{
			t_counted_ptr<t_basic_dialog> dialog = new t_basic_dialog( parent );

			dialog->add_experience_icon();

			std::string text;
			if ( maxed_out_heroes.size() == 1 )
			{
				text = replace_keywords( k_max_level_reached, maxed_out_heroes.front() );
			}
			else
			{
				text = replace_keywords( k_max_level_reached_multiple, maxed_out_heroes );
			}
			dialog->set_text( text );
			dialog->add_ok_button();
			dialog->set_title( k_max_level_reached_title );
			dialog->open();
			dialog->run_modal();
		}
	}
}

// ------------------------------------------------------
// array of creatures and/or heroes
// consolidate stacks
// ------------------------------------------------------
void t_creature_array::consolidate()
{
	int                  i, j;
	t_creature_stack_ptr stack;

	for (i = 1; i < k_size; i++)
	{
		stack = m_data[i];
		if (stack->get_number() == 0)
			continue;
		if (stack->get_creature_type() == k_creature_none)
			continue;
		for (j = 0; j < i; j++)
		{
			if (m_data[j]->get_creature_type() == stack->get_creature_type())
			{
				m_data[j]->get_creature()->add( *stack->get_creature() );
				clear( i );
				break;
			}
		}
	}	

	post_change();

}


// ------------------------------------------------------
// Can we combine two creature arrays into
// a single array of creatures?
// ------------------------------------------------------
bool can_combine( t_creature_array const & first, t_creature_array const & second )
{
	// We can combine if there are less than 7 heroes + unique types of creatures 
	typedef std::bitset< k_creature_type_count > t_creature_type_bitset;

	t_creature_type_bitset creature_types;
	int hero_count = 0;

	creature_types.reset();

	int array; // First or second creature array argument
	int i;

	for ( array = 0; array < 2; array++ )
	{
		t_creature_array const & cur_array = (array == 0 ? first : second );

		for ( i = 0; i < t_creature_array::k_size; i++ )
		{
			t_creature_stack const & stack = cur_array[i];

			if (stack.get_number() == 0)
				continue;

			if ( stack.get_hero() )
			{
				hero_count++;
			}
			else
			{
				t_creature_type type = stack.get_creature_type();
				if ( type != k_creature_none )
				{
					creature_types.set( type );
				}
			}
		}
	}

	return hero_count + creature_types.count() <= t_creature_array::k_size;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// forward the preplacement call to the stacks
// ------------------------------------------------------
bool t_creature_array::preplacement( t_adventure_map& map, int pass, t_player* owner )
{
	bool result = false;

	int slot_num;
	for ( slot_num = 0; slot_num < k_size; ++slot_num )
		result = m_data[ slot_num ]->preplacement( map, pass, owner ) || result;

	return result;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
void t_creature_array::swap( t_creature_array& other )
{
	std::swap( m_initial_location, other.m_initial_location );
	std::swap( m_patrol_type, other.m_patrol_type );
	std::swap( m_patrol_radius, other.m_patrol_radius );
	std::swap( m_ai_data_cache, other.m_ai_data_cache );
	std::swap( m_ai_importance, other.m_ai_importance );

	std::swap_ranges( &m_data[ 0 ], &m_data[ k_size ], &other.m_data[ 0 ] );

	post_change();

	other.post_change();
}

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
void t_creature_array::swap_creatures( t_creature_array& other )
{
	std::swap_ranges( &m_data[ 0 ], &m_data[ k_size ], &other.m_data[ 0 ] );

	post_change();

	other.post_change();
}

// ------------------------------------------------------
// array of creatures and/or heroes
// get highest skill present
// ------------------------------------------------------
t_skill_mastery	t_creature_array::get_skill( t_skill_type skill, t_hero** hero ) const
{
	t_skill_mastery result = k_mastery_none;
	t_skill_mastery level;
	int				i;

	if (hero != 0)
		*hero = 0;
	for (i = 0; i < k_size; ++i)
	{
		if (m_data[i]->get_number() == 0 || m_data[i]->is_dead())
			continue;
		if (m_data[i]->get_wounds() >= m_data[i]->get_hit_points())
			continue;
		level = m_data[i]->get_skill( skill );
		if (level > result)
		{
			result = level;
			if (hero != 0)
				*hero = m_data[i]->get_hero();
		}
	}
	return result;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// get most power full skill present
// ------------------------------------------------------
t_hero const* t_creature_array::get_most_powerful_skill_const( t_skill_type skill ) const
{
	int				best_power = 0;
	int				power = 0;
	t_hero*			result = 0;
	t_hero*			hero;
	int				i;

	for (i = 0; i < k_size; ++i)
	{
		hero = m_data[i]->get_hero();
		if (hero == 0)
			continue;
		if (hero->get_number() == 0 || hero->is_dead())
			continue;
		if (hero->get_wounds() >= hero->get_hit_points())
			continue;
		power = hero->get_skill_power( skill );
		if (power > best_power)
		{
			result = hero;
			best_power = power;
		}
	}
	return result;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// get most powerful skill present
// ------------------------------------------------------
int t_creature_array::get_most_powerful_skill_power( t_skill_type skill ) const
{
	t_hero const* hero = get_most_powerful_skill( skill );

	if (hero == 0)
		return 0;
	return hero->get_skill_power( skill );
}


// ------------------------------------------------------
// add a temporary bonus to all stacks in the array.
// ------------------------------------------------------
void t_creature_array::add_bonus( t_stat_type stat, int amount )
{
	for (int loop = 0; loop < k_size; loop++)
	{
		t_creature_stack* creature = m_data[loop];
		if (creature) 
			creature->add_temp_bonus(stat, amount);
	}
}

// ------------------------------------------------------
// get best discount for creature purchase due to artifacts
// ------------------------------------------------------
int t_creature_array::get_recruitment_discount() const
{
	int			  result = 0;
	int			  discount;
	int			  i;
	t_hero const* hero;

	for (i = 0; i < k_size; ++i)
	{
		hero = m_data[i]->get_hero();
		if (hero == 0)
			continue;
		discount = get_artifact_recruitment_discount( *hero );
		if (result < discount)
			result = discount;
	}
	return result;
}

// ------------------------------------------------------
// check if any hero has the seaman's hat equipped
// ------------------------------------------------------
bool t_creature_array::has_seamans_hat() const
{
	int			  i;
	t_hero const* hero;

	for (i = 0; i < k_size; ++i)
	{
		hero = m_data[i]->get_hero();
		if (hero == 0)
			continue;
		if (::has_seamans_hat( *hero ))
			return true;
	}
	return false;
}

// ------------------------------------------------------
// increase / decrease movement for all creatures.
// ------------------------------------------------------
void t_creature_array::change_movement( int amount )
{
	bool				in_boat = is_boat();
	float				move_bonus = get_move_bonus( in_boat );
	float				multiplier = get_move_multiplier( in_boat );
	float				fastest_raw_move = get_fastest_raw_move();
	float				modifier;
	int					i;
	t_creature_stack*	stack;

	for (i = 0; i < k_size; ++i)
	{
		stack = m_data[i];
		if (stack->get_number() == 0 || stack->is_dead())
			continue;
		modifier = stack->get_adventure_movement_modifier( move_bonus, multiplier,
														   fastest_raw_move );
		stack->change_raw_adventure_movement( amount / modifier );
	}
}


// ------------------------------------------------------
// get remaining movement, including all modifiers.
// ------------------------------------------------------
int t_creature_array::get_movement( bool in_boat ) const
{
	float	move_bonus = get_move_bonus( in_boat );
	float	multiplier = get_move_multiplier( in_boat );
	float	fastest_raw_move = get_fastest_raw_move();
	float   modifier;
	float   raw_movement_left;
	int		i;
	int		movement;
	bool	first = true;
	int		result = 0;
	t_creature_stack const* stack;

	for (i = 0; i < k_size; ++i)
	{
		stack = m_data[i];
		if (stack->get_number() == 0 || m_data[i]->is_dead())
			continue;
		modifier = stack->get_adventure_movement_modifier( move_bonus, multiplier,
														   fastest_raw_move );
		raw_movement_left = stack->get_raw_adventure_movement_left();
		movement = ( raw_movement_left * modifier ) + 0.5;
		if (first || result > movement )
			result = movement;
		first = false;
	}
	return result;
}

// ------------------------------------------------------
// get maximum possible movement, including all modifiers
// ------------------------------------------------------
int t_creature_array::get_max_movement( bool in_boat ) const
{
	float	move_bonus = get_move_bonus( in_boat );
	float	multiplier = get_move_multiplier( in_boat );
	float	fastest_raw_move = get_fastest_raw_move();
	float   modifier;
	float   raw_movement;
	int		i;
	int		movement;
	bool	first = true;
	int		result = 0;
	t_creature_stack const* stack;

	for (i = 0; i < k_size; ++i)
	{
		stack = m_data[i];
		if (stack->get_number() == 0 || m_data[i]->is_dead())
			continue;
		modifier = stack->get_adventure_movement_modifier( move_bonus, multiplier,
														   fastest_raw_move );
		raw_movement = stack->get_raw_adventure_movement();
		movement = ( raw_movement * modifier ) + 0.5;
		if (first || result > movement )
			result = movement;
		first = false;
	}
	return result;
}

// ------------------------------------------------------
// add a temporary move bonus
// ------------------------------------------------------
bool t_creature_array::add_move_bonus( int								  amount, 
		                               t_qualified_adv_object_type const& object_type,
									   int								  days )
{
	int					i;
	bool				result = false;
	t_creature_stack*	stack;
	int					days_left;

	for (i = 0; i < k_size; ++i)
	{
		stack = m_data[i];
		if (stack->get_number() == 0)
			continue;
		days_left = stack->get_bonus_time( object_type );
		if (days_left == 0)
			stack->change_raw_adventure_movement( amount );
		if (stack->add_timed_bonus( k_stat_movement, amount, object_type, days ))
			result = true;
	}
	return result;
}

// ------------------------------------------------------
// get lowest timed bonus
// ------------------------------------------------------
int t_creature_array::get_shortest_bonus( t_qualified_adv_object_type const& object_type ) const
{
	int					i;
	int					result = 0;
	bool				found = false;
	t_creature_stack*	stack;
	int					days_left;

	for (i = 0; i < k_size; ++i)
	{
		stack = m_data[i];
		if (stack->get_number() == 0)
			continue;
		// get time left
		days_left = stack->get_bonus_time( object_type );
		// if this is the first real stack, or this result is lower than 
		// the result so far, record it.
		if (found && days_left > result)
			continue;
		result = days_left;
		found = true;
	}
	return result;
}

// ------------------------------------------------------
// Override to do any special processing needed after 
// the list of creatures changes
// ------------------------------------------------------
void t_creature_array::post_change(void)
{
}

// ------------------------------------------------------
// The creatures come to town
// ------------------------------------------------------
void t_creature_array::visit_town( t_abstract_town * town )
{
	for (int i = 0; i < k_size; i++)
	{
		t_hero *hero = m_data[i]->get_hero();

		if (hero)
		{
			hero->visit_town( town, *this);
		}
	}
}

// ------------------------------------------------------
// ------------------------------------------------------
void t_creature_array::set_patrol_radius( t_int8 radius )
{
	m_patrol_radius = radius;
}

// ------------------------------------------------------
// ------------------------------------------------------
void t_creature_array::set_patrol_type( t_patrol_type type )
{
	m_patrol_type = type;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
bool t_creature_array::is_in_patrol_radius( t_adv_map_point const& point ) const
{
	if (m_patrol_radius != -1) 
	{
		int square_distance = m_patrol_radius * m_patrol_radius;

		int row_distance = point.row - m_initial_location.row;
		int col_distance = point.column - m_initial_location.column;
		return (row_distance * row_distance + col_distance * col_distance) <= square_distance;
	}
	return true;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
float t_creature_array::ai_value() const
{
	float generalship_modifier = 1.0f + ai_bonus_for_generalship_skills(this);

	float total_value = 0.0f;
	for ( int i = 0; i < k_size; i++ ) 
	{
		t_creature_stack const* stack = m_data[i].get();
		float stack_value = stack->ai_value( this );

		if (stack->get_const_creature())
			stack_value *= generalship_modifier;

		total_value += stack_value;
	}
	return total_value;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
float t_creature_array::ai_value_including_dead() const
{
	float stack_value;
	float generalship_modifier = 1.0f + ai_bonus_for_generalship_skills(this, true);

	float total_value = 0.0f;
	for ( int i = 0; i < k_size; i++ ) 
	{
		t_creature_stack const* stack = m_data[i].get();
		t_hero const* hero = stack->get_const_hero();

		if (hero == NULL)
			stack_value = stack->ai_value( this );
		else 
			stack_value = hero->ai_value_including_dead();

		if (stack->get_const_creature())
			stack_value *= generalship_modifier;

		total_value += stack_value;
	}
	return total_value;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
float t_creature_array::ai_value_creatures(bool include_generalship) const
{
	float generalship_modifier = 1.0f + ai_bonus_for_generalship_skills(this);

	float value = 0.0f;
	for (int i = 0; i < t_creature_array::k_size; i++) 
	{
		t_creature_stack const* stack = m_data[i].get();
		if ( stack->get_creature() )
			value += stack->ai_value() * generalship_modifier;
	}
	return value;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
t_creature_stack const* t_creature_array::ai_get_most_powerful( float& value, float& total_value ) const
{
	float generalship_modifier = 1.0f + ai_bonus_for_generalship_skills(this);

	t_creature_stack const* best_stack = NULL;
	value = total_value = 0.0f;

	for (int i = 0; i < t_creature_array::k_size; i++) 
	{
		t_creature_stack const* stack = m_data[i].get();
		float stack_value = stack->ai_value();
		if ( stack->get_creature() ) 
			stack_value *= generalship_modifier;

		if (value < stack_value)
		{
			value = stack_value;
			best_stack = stack;
		}

		total_value += stack_value;
	}
	return best_stack;
}


// ---------------------------------------------------------------
// ---------------------------------------------------------------
int t_creature_array::compute_scouting_range() const
{
	int result = 0;

	int i;
	for ( i = 0; i < k_size; ++i )
	{
		int range = m_data[ i ]->compute_scouting_range();
		if ( range > result )
			result = range;
	}

	return result;
}

// ---------------------------------------------------------------
// Are all slots in the army occupied by a creature stack?
// ---------------------------------------------------------------
bool t_creature_array::is_full_army() const
{
	int i;
	for ( i = 0; i < k_size; ++i )
	{
		if( m_data[ i ]->get_number() <= 0 )
			return false;
	}

	return true;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
void t_creature_array::ai_start_turn()
{
	m_ai_data_cache->start_turn();

	for (int i = 0; i < k_size; i++) 
		m_data[i]->ai_start_turn();
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
t_adv_map_point const& t_creature_array::get_initial_location() const
{
	return m_initial_location;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
t_ai_army_data_cache* t_creature_array::get_ai_data_cache() const
{
	return m_ai_data_cache.get();
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
void t_creature_array::set_ai_data_cache(t_ai_data_cache_ptr cache_ptr)
{
	m_ai_data_cache = cache_ptr;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
void t_creature_array::set_initial_location(t_adv_map_point const& point)
{
	m_initial_location = point;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
void t_creature_array::copy_extra_properties( t_creature_array const& source )
{
	m_initial_location = source.m_initial_location;
	m_patrol_type = source.m_patrol_type;
	m_patrol_radius = source.m_patrol_radius;
	m_ai_importance = source.m_ai_importance;

	*m_ai_data_cache = *source.m_ai_data_cache;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
void t_creature_array::on_begin_turn()
{
	t_player * owner = get_owner();
	int slot_num;
	for ( slot_num = 0; slot_num < k_size; ++slot_num )
		( *this )[ slot_num ].on_begin_turn( owner, this );
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
void t_creature_array::on_end_turn()
{
	t_player * owner = get_owner();
	int slot_num;
	for ( slot_num = 0; slot_num < k_size; ++slot_num )
		( *this )[ slot_num ].on_end_turn( owner, this );
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
t_creature_array* t_creature_array::get_creature_array()
{
	return this;
}

// ---------------------------------------------------------------------
// given certain information, convert raw movement to displayed 
// movement.
// ---------------------------------------------------------------------
float t_creature_array::get_movement_modifier( t_creature_stack const& stack, bool in_boat ) const
{
	float move_bonus = get_move_bonus( in_boat );
	float multiplier = get_move_multiplier( in_boat );
	float fastest_raw_move = 0.0;
	
	if (stack.get_hero() != 0)
		fastest_raw_move = get_fastest_raw_move();
	return stack.get_adventure_movement_modifier( move_bonus, multiplier, fastest_raw_move );
}

// ---------------------------------------------------------------------
// compute amount to add to an army's movement
// based on artifacts, etc. in creatures.
// ---------------------------------------------------------------------
int t_creature_array::get_move_bonus( bool in_boat ) const
{
	int	result = 0;
	int	bonus;
	int	i;

	for (i = 0; i < k_size; ++i)
	{
		bonus = m_data[i]->get_army_move_bonus( in_boat );
		if (result < bonus)
			result = bonus;
	}
	if (in_boat && get_map() != 0 )
	{
		if (get_map()->get_team_lighthouse_count( get_owner_number() ) > 0)
			result += k_lighthouse_bonus;
	}
	return result;
}

// ---------------------------------------------------------------------
// compute amount to multiply an army's movement for skills, etc.
// ---------------------------------------------------------------------
float t_creature_array::get_move_multiplier( bool in_boat ) const
{
	if (in_boat)
		return 0.0f;

	float	result = 1.0f;
	float	multiplier;
	int		i;

	for (i = 0; i < k_size; ++i)
	{
		multiplier = m_data[i]->get_army_move_multiplier( in_boat );
		if (result < multiplier)
			result = multiplier;
	}
	return result;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
bool t_creature_array::is_alive() const
{
	for (int index = 0; index < k_size; index++)
		if ( (m_data[index]->get_number() > 0) && !m_data[index]->is_dead() )
			return true;
	
	return false;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
t_skill_mastery t_creature_array::get_anti_stealth_level() const
{
	t_skill_mastery result = k_mastery_none;

	int slot_num;
	for ( slot_num = 0; slot_num < k_size; ++slot_num )
	{
		if ( m_data[ slot_num ]->get_number() <= 0 )
			continue;

		t_skill_mastery anti_stealth_level = m_data[ slot_num ]->get_anti_stealth_level();
		if ( result < anti_stealth_level )
			result = anti_stealth_level;
	}

	return result;
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------
t_skill_mastery t_creature_array::get_stealth_level() const
{
	t_skill_mastery			result = k_mastery_grand_master;
	int						slot_num;
	bool					any_living = false;
	t_creature_stack const*	stack;

	for ( slot_num = 0; slot_num < k_size; ++slot_num )
	{
		stack = m_data[slot_num];
		if ( stack->get_number() <= 0 || stack->is_dead() )
			continue;

		any_living = true;
		t_skill_mastery stealth_level = stack->get_stealth_level();

		if ( result > stealth_level )
			result = stealth_level;
	}
	if (!any_living)
		result = k_mastery_none;
	return result;
}

void t_creature_array::set_in_combat( bool arg )
{
}

bool t_creature_array::is_aquatic() const 
{
	// Only neutral armies can have meraids and sea-monsters.
	if (get_owner() != NULL)
		return false;

	bool has_aquatic = false;

	for (int i = 0; i < t_creature_array::k_size; i++)
	{
		if (m_data[i]->get_const_hero() != NULL)
			return false;
		
		t_creature_type type = m_data[i]->get_creature_type();
	
		if (type == k_creature_none)
			continue;

		if ((type == k_sea_monster) || (type == k_mermaid))
			has_aquatic = true;
		else
			return false;
	}
	
	return has_aquatic;
}

// ---------------------------------------------------------------
// check heroes for level increases 
// ---------------------------------------------------------------
void t_creature_array::check_hero_levels( bool show_dialogs )
{
	int i;

	for ( i = 0; i < k_size; i++) 
	{
		t_hero* hero = m_data[i]->get_hero();
		
		if (hero)
		{
			t_adventure_frame* frame;
			
			if (show_dialogs)
				frame = get_adventure_frame();
			else
				frame = 0;

			hero->check_level( *get_map(), frame, get_owner() );
			hero->update_class( show_dialogs && is_human() );
		}
	}
}

// ---------------------------------------------------------------
// default selection behavior does nothing 
// ---------------------------------------------------------------
bool t_creature_array::select()
{
	return false;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
static int choose_slot( t_creature_array const& army, t_creature_type creature,
					    int const* slots, int slot_count )
{
	int i;

	for (i = 0; i < slot_count; i++)
		if (army[slots[i]].can_add( creature ))
			return slots[i];
	return -1;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
void add_start_creature( t_creature_array& garrison, t_town_type town_type,
						 t_town_building building )
{
	t_building_traits const& building_traits = get_traits( town_type, building );
	t_creature_type			 creature		 = building_traits.creature;
	t_creature_traits const& creature_traits = get_traits( creature );
	int						 amount			 = creature_traits.weekly_growth;
	int						 slot;
	static int const	     k_ranged_slots[3] = { 3, 1, 5 };
	static int const		 k_melee_slots[4] = { 2, 4, 0, 6 };
	
	if (creature_traits.has_ability( k_ability_ranged ))
	{
		slot = choose_slot( garrison, creature, k_ranged_slots, 
			                ELEMENTS_OF( k_ranged_slots ));
		if (slot < 0)
			slot = choose_slot( garrison, creature, k_melee_slots, 
			                    ELEMENTS_OF( k_melee_slots ));
	}
	else
	{
		slot = choose_slot( garrison, creature, k_melee_slots, 
			                ELEMENTS_OF( k_melee_slots ));
		if (slot < 0)
			slot = choose_slot( garrison, creature, k_ranged_slots, 
								ELEMENTS_OF( k_ranged_slots ));
	}
	if (slot >= 0)
		garrison.add( creature, amount, slot );
}

